import getpass,traceback,tkinter,tkinter.messagebox
import os,psutil,subprocess,signal,sys,inspect,ctypes
import pyperclip,windnd
from tkinter import *

username = getpass.getuser()
# 创建临时文件夹
make_dir = 'C:\\Users\\' + username + '\\Documents\\DA_Tools\\'
crawler_path = make_dir + 'crawler_book_temp'
# 工具全局监控异常日志
traceback_log = make_dir + 'traceback.log'
path_log = crawler_path + 'windnd_path.log'


def resource_path(relative_path):
    """生成资源文件目录访问路径"""
    if getattr(sys, 'frozen', False):
        base_path = sys._MEIPASS
    else:
        base_path = os.path.abspath('.')
    return os.path.join(base_path, relative_path)

def execute_cmd(cmd):
    proc = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.STDOUT,stdin=subprocess.PIPE)
    proc.stdin.close()
    proc.wait()
    try:
        result = proc.stdout.read().decode('gbk')  # 注意你电脑cmd的输出编码（中文是gbk）
    except UnicodeDecodeError:
        result = proc.stdout.read().decode('utf-8')  # 适用于截图录屏功能，针对截图录屏文件名中文编码报错的异常处理
    proc.stdout.close()
    return result


def crawler_tools_log(fun_name):
    # 捕获异常装饰器
    def log(*args, **kwargs):
        try:
            fun_name(*args, **kwargs)
        except Exception:
            traceback.print_exc()
            # 记录异常
            with open(traceback_log,'w') as fp:
                fp.write(str(traceback.format_exc()))
            content = '''
            功能发生异常，请联系开发者596044192@qq.com进行修复
            异常日志已保存在{}
            点击“确定”后会自动关闭本工具，请重新启动使用即可！
            '''
            tkinter.messagebox.showinfo('异常',content.format(traceback_log))
            # 强制结束python.exe程序
            # execute_cmd('taskkill /F /IM %s ' % 'python.exe /T')
            pid = os.getpid()  # 获取当前程序pid
            pid_name = psutil.Process(pid).name()  # 根据pid获取当前程序名
            # 强制结束当前程序
            execute_cmd('taskkill /F /IM %s ' % pid_name + ' /T')
            pid = os.getpid()
            os.kill(pid,signal.SIGINT)
            sys.exit()
    return log


def resource_path(relative_path):
    """生成资源文件目录访问路径"""
    if getattr(sys, 'frozen', False):
        base_path = sys._MEIPASS
    else:
        base_path = os.path.abspath('.')
    return os.path.join(base_path, relative_path)


# 获取包名所有信息
package_log_path = resource_path(os.path.join('temp','package_log.txt'))
packages_name = resource_path(os.path.join('temp','packages_name.log'))


def _async_raise(tid, exctype):
    """Raises an exception in the threads with id tid"""
    if not inspect.isclass(exctype):
        raise TypeError("Only types can be raised (not instances)")
    res = ctypes.pythonapi.PyThreadState_SetAsyncExc(ctypes.c_long(tid), ctypes.py_object(exctype))
    if res == 0:
        raise ValueError("invalid thread id")
    elif res != 1:
        # """if it returns a number greater than one, you're in trouble,
        # and you should call it again with exc=NULL to revert the effect"""
        ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, None)
        raise SystemError("PyThreadState_SetAsyncExc failed")


def stop_thread(thread):
    # 终止进程
    _async_raise(thread.ident, SystemExit)


def pyperclip_copy_paste(content):
    # 通用复制粘贴
    pyperclip.copy(content)
    # 从剪贴板那粘贴
    pyperclip.paste()
    tkinter.messagebox.showinfo('粘贴提醒','已复制粘贴\n' + content + '\n到剪贴板\n温馨提示：可以Ctrl+V粘贴到浏览器进行打开~')


def windnd_hook_files(widget,widget_str):
    # 拖拽文件到entry文本框获取文件路径功能（windnd） widget是控件 widget_str是显示文件路径
    def dragged_files(files):
        # 获取文件路径
        widget_str.set('')
        path_msg = '\n'.join((item.decode('gbk') for item in files))
        print('获取的文件路径：' + path_msg)
        with open(path_log,'w') as fp:
            fp.write(path_msg)
        fp.close()
        widget.insert(tkinter.END,path_msg)

    # 使用windnd方法
    windnd.hook_dropfiles(widget,func=dragged_files)


# 当鼠标移动到指定控件时，进行文字提醒的控件
class ToolTip(object):

    def __init__(self, widget):
        self.widget = widget
        self.tipwindow = None
        self.id = None
        self.x = self.y = 0

    # 当光标移动指定控件是显示消息
    def showtip(self, text):
        "Display text in tooltip window"
        self.text = text
        if self.tipwindow or not self.text:
            return
        x, y, cx, cy = self.widget.bbox("insert")
        x = x + self.widget.winfo_rootx()+15
        y = y + cy + self.widget.winfo_rooty()+25
        self.tipwindow = tw = Toplevel(self.widget)
        tw.wm_overrideredirect(True)
        tw.wm_geometry("+%d+%d" % (x, y))
        label = Label(tw, text=self.text,justify=LEFT,
                      background="Yellow", relief=SOLID, borderwidth=1,
                      font=("微软雅黑", "10"))
        label.pack(side=BOTTOM)

    # 当光标移开时提示消息隐藏
    def hidetip(self):
        tw = self.tipwindow
        self.tipwindow = None
        if tw:
            tw.destroy()

# 气泡提示的函数（可调用）
"""
第一个参数：是定义的控件的名称
第二个参数，是要显示的文字信息
"""
def CreateToolTip(widget, text):
    toolTip = ToolTip(widget)

    def enter(event):
        toolTip.showtip(text)

    def leave(event):
        toolTip.hidetip()
    widget.bind('<Enter>', enter)
    widget.bind('<Leave>', leave)

